﻿using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using AutoMapper;
using MediatR;
using Microsoft.IdentityModel.Tokens;
using Provenance.Domain;
using Provenance.ErrorCount;
using Provenance.Infra;
using Provenance.Infra.Interfaces.User;
using Provenance.Read.Api.Application.Command.User;
using Provenance.Read.Api.Dto.User;
using Provenance.Read.Api.Jwt;

namespace Provenance.Read.Api.Application.CommandHandler.User
{
    public class LoginCommandHandler : IRequestHandler<LoginCommand, ApiResult<LoginResponseDTO>>
    {
        private readonly IUserInfoRepository _userRepository;
        private readonly IMapper _mapper;
        private readonly ILogger<LoginCommandHandler> _logger;
        private readonly JwtSettings _jwtSettings;
        /// <summary>
        /// 依赖注入
        /// </summary>
        /// <param name="userRepository">IOC容器Autofac，IUserInfoRepository注入</param>
        /// <param name="mapper"></param>
        /// <param name="logger"></param>
        /// <param name="jwtTokenGenerator"></param>
        public LoginCommandHandler(IUserInfoRepository userRepository, IMapper mapper, ILogger<LoginCommandHandler> logger, JwtSettings jwtSettings)
        {
            _userRepository = userRepository;
            _mapper = mapper;
            _logger = logger;
            _jwtSettings = jwtSettings;
        }
        public async Task<ApiResult<LoginResponseDTO>> Handle(LoginCommand request, CancellationToken cancellationToken)
        {
            try
            {
                var obj = await _userRepository.GetAsync(x => x.UserName == request.UserName);
                if (obj == null)
                {
                    return ApiResult<LoginResponseDTO>.Failure("用户名不存在");
                }
                if (obj.Password != request.Password)
                {
                    if (obj.ErrorCount >= 3)
                    {
                        obj.IsLocked = true;
                        await _userRepository.UpdateEntity(obj);
                        return ApiResult<LoginResponseDTO>.Failure("密码错误3次，账号已被锁定");
                    }
                    else
                    {
                        obj.ErrorCount += 1;
                        await _userRepository.UpdateEntity(obj);
                        return ApiResult<LoginResponseDTO>.Failure("密码错误，还有" + (4 - obj.ErrorCount) + "次机会");
                    }
                }
                else
                {
                    obj.ErrorCount = 0;
                    await _userRepository.UpdateEntity(obj);
                    var response = _mapper.Map<LoginResponseDTO>(obj);
                    // 登录成功生成JWT Token
                    response.strToken = GenerateToken(response.UserName, response.UserId);
                    _logger.LogInformation("测试测试测试测试测试测试测试测试测试");
                    return ApiResult<LoginResponseDTO>.Success(response);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while logging in" + ex.Message);
                return ApiResult<LoginResponseDTO>.Failure("Error while logging in" + ex.Message);
            }
        }
        /// <summary>
        /// 生成 JWT Token
        /// </summary>
        /// <param name="username"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public string GenerateToken(string username, int userId)
        {
            // 设置 token 的过期时间
            var expiryDate = DateTime.UtcNow.AddMinutes(60); // 例如，60分钟后过期

            // 创建 claims
            var claims = new[]
            {
            new Claim(ClaimTypes.Name, username),
            new Claim(ClaimTypes.NameIdentifier, userId.ToString())
            };

            // 创建密钥
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            // 创建 JWT
            var token = new JwtSecurityToken(
                issuer: _jwtSettings.Issuer,
                audience: _jwtSettings.Audience,
                claims: claims,
                expires: expiryDate,
                signingCredentials: creds);

            return new JwtSecurityTokenHandler().WriteToken(token);
        }


    }
}
